package com.md.util;

import com.md.util.es.Query;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 刘骄阳
 * 2021-11-20 10:14
 */
@Configuration
@ConditionalOnClass({RestHighLevelClient.class})
@ConditionalOnBean({RestHighLevelClient.class})
public class ElasticSearchUtil {
  @Resource
  private RestHighLevelClient restHighLevelClient;

  /**
   * 批量新增es数据
   *
   * @param index 增加到哪一个索引
   * @param map   数据 Map<id,实体类>
   */
  public <T> void insert(final String index, final Map<String, T> map) {
    if (!map.isEmpty()) {
      BulkRequest bulkRequest = new BulkRequest();
      //设置索引
      IndexRequest indexRequest;
      //将list集合中的数据存入indexRequest中
      for (final Map.Entry<String, T> entry : map.entrySet()) {
        indexRequest = new IndexRequest(index);
        //设置id
        indexRequest.id(entry.getKey());
        //序列化数据后,存入indexRequest
        indexRequest.source(StringUtil.objectToJson(entry.getValue()), XContentType.JSON);
        //追加进bulkRequest
        bulkRequest.add(indexRequest);
      }
      try {
        restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * 根据id批量删除数据
   *
   * @param index 删除到哪一个索引
   * @param ids   要删除的索引id
   */
  public void delete(final String index, final String... ids) {
    BulkRequest bulkRequest = new BulkRequest();
    //设置索引
    DeleteRequest deleteRequest;
    //将id存入deleteRequest中
    for (String id : ids) {
      //初始化要删除的索引id
      deleteRequest = new DeleteRequest(index, id);
      //追加进bulkRequest
      bulkRequest.add(deleteRequest);
    }
    try {
      restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 批量更新es数据
   *
   * @param index 更新到哪一个索引
   * @param map   数据 Map<id,实体类>
   */
  public <T> void update(final String index, final Map<String, T> map) {
    if (!map.isEmpty()) {
      BulkRequest bulkRequest = new BulkRequest();
      //设置索引
      UpdateRequest updateRequest;
      //将list集合中的数据存入updateRequest中
      for (final Map.Entry<String, T> entry : map.entrySet()) {
        //设置id
        updateRequest = new UpdateRequest(index, entry.getKey());
        //序列化数据后,存入updateRequest
        updateRequest.doc(StringUtil.objectToJson(entry.getValue()), XContentType.JSON);
        //追加进bulkRequest
        bulkRequest.add(updateRequest);
      }
      try {
        restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * 更新es数据
   *
   * @param index 更新到哪一个索引
   * @param id    指定更新的索引id
   * @param map   更新指定的数据
   */
  public void update(final String index, final String id, final Map<String, String> map) {
    BulkRequest bulkRequest = new BulkRequest();
    //设置索引
    UpdateRequest updateRequest;
    //设置id
    updateRequest = new UpdateRequest(index, id);
    //根据map键值设置列名与值
    map.forEach(updateRequest::doc);
    //追加进bulkRequest
    bulkRequest.add(updateRequest);
    try {
      restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 查询
   *
   * @param index 索引
   * @param query 查询条件
   * @param clazz 类型
   * @param <T>   类型
   * @return 查询结果
   */
  public <T> List<T> select(final String index, final Query query, final Class<T> clazz) {
    List<T> list = new ArrayList<>();
    // 负责设置搜索参数
    SearchRequest request = new SearchRequest(index);
    // 构建搜索条件
    request.source(query.getBuilder());
    try {
      SearchResponse search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
      SearchHits hits = search.getHits();
      SearchHit[] valueArray = hits.getHits();

      for (SearchHit fields : valueArray) {
        Map<String, Object> map = fields.getSourceAsMap();
        list.add(StringUtil.jsonToObject(mapToJson(map), clazz));
      }

    } catch (IOException e) {
      e.printStackTrace();
    }
    return list;
  }

  private String mapToJson(final Map<String, Object> map) {
    map.forEach((key, value) -> map.put(StringUtil.lineToHump(key), value));
    return StringUtil.objectToJson(map);
  }
}
